package com.nykredit.kundeservice.swing;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.EnumSet;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.Dimension;
import org.jdesktop.swingx.JXDatePicker;
import org.joda.time.DateTime;
import org.joda.time.DateTimeField;
import org.joda.time.DateTimeFieldType;
import org.joda.time.Period;
import org.joda.time.format.DateTimeFormat;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.Font;
public class PeriodSelector extends JPanel implements ActionListener {
private static final long serialVersionUID = 1L;
public enum SelectionMode{
DAY("Dag"),
WEEK("Uge"),
MONTH("M�ned"),
YEAR("�r");
private String name;
SelectionMode(String name){
this.name = name;
}
@Override
public String toString() {
return this.name;
}
}
private boolean showLowerBoundLabels = true;
protected DateTime lowerBound;
protected DateTime upperBound;
protected int numberOfPeriods = 1;
protected EnumSet<SelectionMode> selectionModes = EnumSet.allOf(SelectionMode.class);
private final JComboBox cboSelectionMode = new JComboBox();
private final JXDatePicker cboDay = new JXDatePicker();
private final JComboBox cboWeek = new JComboBox();
private final JComboBox cboMonth = new JComboBox();
private final JComboBox cboYear = new JComboBox();
private final JLabel lblLowerBound = new JLabel("Fra:");
private final JLabel lblLowerBoundDate = new JLabel();
private final JLabel lblUpperBound = new JLabel("V�lg dato:");
private ArrayList<ActionListener> actionListeners = new ArrayList<ActionListener>();
public boolean getShowLowerBoundLabels(){
return this.showLowerBoundLabels;
}
public void setShowLowerBoundLabels(boolean showLowerBoundLabels){
this.showLowerBoundLabels = showLowerBoundLabels;
}
public DateTime getMinimumDate(){
return this.lowerBound;
}
public void setLowerBound(DateTime lowerBound){
if(lowerBound == null){
this.lowerBound = new DateTime(2008, 2, 1, 00, 00, 00);
} else
this.lowerBound = lowerBound;
}
public DateTime getLowerBound(){
return this.lowerBound;
}
public void setUpperBound(DateTime maximumDate){
if(maximumDate == null)
this.upperBound = new DateTime();
else
this.upperBound = maximumDate;
}
public DateTime getUpperBound(){
return this.lowerBound;
}
public int getNumberOfPeriods(){
return this.numberOfPeriods;
}
public void setNumberOfPeriods(int numberOfPeriods){
this.numberOfPeriods = numberOfPeriods;
}
public SelectionMode[] getSelectionModes(){
return this.selectionModes.toArray(new SelectionMode[0]);
}
public void setSelectionModes(EnumSet<SelectionMode> selectionModes){
if(selectionModes == null)
throw new IllegalArgumentException("Selection modes cannot be null.");
else if(selectionModes.isEmpty())
throw new IllegalArgumentException("Selection modes cannot be empty.");
this.selectionModes.clear();
DefaultComboBoxModel theModel = (DefaultComboBoxModel)this.cboSelectionMode.getModel();
theModel.removeAllElements();
this.selectionModes = EnumSet.allOf(SelectionMode.class);
this.updateCboSelectionMode();
}
public boolean getCanSelectDay(){
return this.selectionModes.contains(SelectionMode.DAY);
}
public void setCanSelectDay(boolean canSelectDay){
if(this.getCanSelectDay() == false)
this.selectionModes.add(SelectionMode.DAY);
}
public boolean getCanSelectWeek(){
return this.selectionModes.contains(SelectionMode.WEEK);
}
public void setCanSelectWeek(boolean canSelectWeek){
if(this.getCanSelectWeek() == false)
this.selectionModes.add(SelectionMode.WEEK);
}
public boolean getCanSelectMonth(){
return this.selectionModes.contains(SelectionMode.MONTH);
}
public void setCanSelectMonth(boolean canSelectMonth){
if(this.getCanSelectMonth() == false)
this.selectionModes.add(SelectionMode.MONTH);
}
public boolean getCanSelectYear(){
return this.selectionModes.contains(SelectionMode.YEAR);
}
public void setCanSelectYear(boolean canSelectYear){
if(this.getCanSelectYear() == false)
this.selectionModes.add(SelectionMode.YEAR);
}
public SelectionMode getCurrentSelectedMode(){
return (SelectionMode)this.cboSelectionMode.getSelectedItem();
}
public void setCurrentSelectedMode(SelectionMode selectionMode){
if(selectionMode == null)
throw new IllegalArgumentException("Selection mode cannot be null.");
boolean cboSelectionModeContainsAssignedMode = false;
for(int i = 0; i < this.cboSelectionMode.getItemCount(); i++)
if(this.cboSelectionMode.getItemAt(i).equals(selectionMode))
cboSelectionModeContainsAssignedMode = true;
if(cboSelectionModeContainsAssignedMode == false)
throw new IllegalArgumentException("Cannot assign selection mode " + selectionMode + " in the current state.");
this.cboSelectionMode.setSelectedItem(selectionMode);
}
public DateTime getSelectedPeriodLowerBound(){
SelectionMode selectedMode = (SelectionMode)this.cboSelectionMode.getSelectedItem();
DateTime lowerBound = null;
if(selectedMode == SelectionMode.DAY)
if(this.cboDay.getDate() != null){
DateTime selectedDate = new DateTime(this.cboDay.getDate());
lowerBound = selectedDate.minusDays(this.numberOfPeriods);
}
else if(selectedMode == SelectionMode.WEEK)
if(this.cboWeek.getSelectedItem() != null)
lowerBound = ((Week)this.cboWeek.getSelectedItem()).getLowerBound();
else if(selectedMode == SelectionMode.MONTH)
if(this.cboMonth.getSelectedItem() != null)
lowerBound = ((Month)this.cboMonth.getSelectedItem()).getLowerBound();
else if(selectedMode == SelectionMode.YEAR)
if(this.cboYear.getSelectedItem() != null)
lowerBound = ((Year)this.cboYear.getSelectedItem()).getLowerBound();
return lowerBound;
}
public DateTime getSelectedPeriodUpperBound(){
SelectionMode selectedMode = (SelectionMode)this.cboSelectionMode.getSelectedItem();
DateTime upperBound = null;
if(selectedMode == SelectionMode.DAY)
if(this.cboDay.getDate() != null)
upperBound = new DateTime(this.cboDay.getDate());
else if(selectedMode == SelectionMode.WEEK)
if(this.cboWeek.getSelectedItem() != null)
upperBound = ((Week)this.cboWeek.getSelectedItem()).getUpperBound();
else if(selectedMode == SelectionMode.MONTH)
if(this.cboMonth.getSelectedItem() != null)
upperBound = ((Month)this.cboMonth.getSelectedItem()).getUpperBound();
else if(selectedMode == SelectionMode.YEAR)
if(this.cboYear.getSelectedItem() != null)
upperBound = ((Year)this.cboYear.getSelectedItem()).getUpperBound();
return upperBound;
}
public Period getSelectedPeriod(){
DateTime lowerBound = this.getSelectedPeriodLowerBound();
DateTime upperBound = this.getSelectedPeriodUpperBound();
Period selectedPeriod = new Period(lowerBound, upperBound);
return selectedPeriod;
}
public PeriodSelector(){
this(null, null, 0);
}
public PeriodSelector(DateTime lowerBound, DateTime upperBound, int numberOfPeriods){
this.setSize(new Dimension(365, 24));
this.setMaximumSize(new Dimension(365, 24));
this.setMinimumSize(new Dimension(365, 24));
setLayout(new FlowLayout(FlowLayout.LEFT, 13, 2));
this.cboSelectionMode.setPreferredSize(new Dimension(70, 20));
this.lblUpperBound.setFont(new Font("Tahoma", Font.BOLD, 11));
this.lblUpperBound.setVisible(false);
this.cboDay.setVisible(false);
this.cboDay.addActionListener(this);
this.cboDay.getEditor().setDisabledTextColor(Color.BLACK);
this.cboDay.getEditor().setEnabled(false);
this.cboWeek.setVisible(false);
this.cboWeek.addActionListener(this);
this.cboMonth.setVisible(false);
this.cboMonth.addActionListener(this);
this.cboYear.setVisible(false);
this.cboYear.addActionListener(this);
this.lblLowerBound.setFont(new Font("Tahoma", Font.BOLD, 11));
this.add(this.cboSelectionMode);
this.add(this.lblUpperBound);
this.add(this.cboDay);
this.add(this.cboWeek);
this.add(this.cboMonth);
this.add(this.cboYear);
this.add(this.lblLowerBound);
this.add(this.lblLowerBoundDate);
this.setLowerBound(lowerBound);
this.setUpperBound(upperBound);
this.numberOfPeriods = numberOfPeriods;
this.updateCboSelectionMode();
this.updateYears();
this.cboSelectionMode.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
PeriodSelector.this.SelectionModeChanged();
PeriodSelector.this.updateLowerBoundLabels();
PeriodSelector.this.dateSelected();
}
});
}
private void updateCboSelectionMode(){
for(SelectionMode s : this.selectionModes)
this.cboSelectionMode.addItem(s);
}
private void SelectionModeChanged(){
if(this.cboSelectionMode.getSelectedItem() == null){
}else{
if(this.cboSelectionMode.getSelectedItem() == SelectionMode.DAY)
this.setSelectionDay();
else if(this.cboSelectionMode.getSelectedItem() == SelectionMode.WEEK)
this.setSelectionWeek();
else if(this.cboSelectionMode.getSelectedItem() == SelectionMode.MONTH)
this.setSelectionMonth();
else if(this.cboSelectionMode.getSelectedItem() == SelectionMode.YEAR)
this.setSelectionYear();
}
}
private void update(){
}
private void updateWeeks(){
Week selectedWeek = (Week)this.cboWeek.getSelectedItem();
this.cboWeek.removeActionListener(this);
DefaultComboBoxModel cboWeekModel = (DefaultComboBoxModel)this.cboWeek.getModel();
cboWeekModel.removeAllElements();
if(this.cboYear.getSelectedItem() != null){
int selectedYear = (Integer)cboYear.getSelectedItem();
int minimumYear = this.lowerBound.getYear();
int minimumWeek = this.lowerBound.getWeekOfWeekyear();
int maximumYear = this.upperBound.getYear();
int maximumWeek = this.upperBound.getWeekOfWeekyear();
Calendar currentYear = Calendar.getInstance();
currentYear.set(Calendar.YEAR, selectedYear);
for(int weekNumber = currentYear.getActualMaximum(Calendar.WEEK_OF_YEAR); weekNumber >= 1; weekNumber--){
if(selectedYear == minimumYear && weekNumber < minimumWeek)
continue;
if(selectedYear == maximumYear && weekNumber > maximumWeek)
continue;
this.cboWeek.addItem(new Week(weekNumber, selectedYear));
}
}
boolean selectedWeekSet = false;
this.cboWeek.addActionListener(this);
if(selectedWeek != null){
for(int i = 0; i < cboWeekModel.getSize(); i++)
if(((Week)cboWeekModel.getElementAt(i)).week == selectedWeek.week){
this.cboWeek.setSelectedIndex(i);
selectedWeekSet = true;
break;
}
if(selectedWeekSet == false)
if(((Week)cboWeekModel.getElementAt(0)).week > selectedWeek.week)
this.cboWeek.setSelectedIndex(0);
else
this.cboWeek.setSelectedIndex(this.cboWeek.getItemCount() - 1);
}
}
private void updateMonths(){
Month selectedMonth = (Month)this.cboMonth.getSelectedItem();
this.cboMonth.removeActionListener(this);
DefaultComboBoxModel cboMonthModel = (DefaultComboBoxModel)this.cboMonth.getModel();
cboMonthModel.removeAllElements();
if(this.cboYear.getSelectedItem() != null){
int selectedYear = (Integer)cboYear.getSelectedItem();
int minimumYear = this.lowerBound.getYear();
int minimumMonth = this.lowerBound.getMonthOfYear();
int maximumYear = this.upperBound.getYear();
int maximumMonth = this.upperBound.getMonthOfYear();
for(int i= 11; i >= 0 ; i--){
if(selectedYear == minimumYear && i < minimumMonth)
continue;
if(selectedYear == maximumYear && i > maximumMonth)
continue;
this.cboMonth.addItem(new Month(i, selectedYear));
}
}
boolean selectedMonthSet = false;
this.cboMonth.addActionListener(this);
if(selectedMonth != null){
for(int i = 0; i < cboMonthModel.getSize(); i++)
if(((Month)cboMonthModel.getElementAt(i)).month == selectedMonth.month){
this.cboMonth.setSelectedIndex(i);
selectedMonthSet = true;
break;
}
if(selectedMonthSet == false){
if(((Month)cboMonthModel.getElementAt(0)).month > selectedMonth.month)
this.cboMonth.setSelectedIndex(0);
else
this.cboMonth.setSelectedIndex(this.cboMonth.getItemCount() - 1);
}
}
}
private void updateYears(){
Year selectedYear = (Year)this.cboYear.getSelectedItem();
this.cboYear.removeActionListener(this);
DateTime dateIterator = this.upperBound;
DefaultComboBoxModel cboYearModel = (DefaultComboBoxModel)this.cboYear.getModel();
cboYearModel.removeAllElements();
while(dateIterator.getYear() >= this.lowerBound.getYear()){
this.cboYear.addItem(new Year(dateIterator.getYear()));
dateIterator = dateIterator.minusYears(1);
}
this.cboYear.addActionListener(this);
if(selectedYear != null && cboYearModel.getSize() > 0){
cboYearModel.setSelectedItem(selectedYear);
if(cboYearModel.getSelectedItem() == null)
if(selectedYear.compareTo((Year) cboYearModel.getElementAt(0)) < 0)
cboYearModel.setSelectedItem(0);
else
cboYearModel.setSelectedItem(cboYearModel.getSize() - 1);
}
}
private void updateLowerBoundLabels(){
if(this.showLowerBoundLabels == false || this.numberOfPeriods == 0){
this.lblLowerBound.setText("");
this.lblLowerBoundDate.setText("");
}else{
this.lblLowerBound.setText("til:");
SelectionMode selectedMode = (SelectionMode)this.cboSelectionMode.getSelectedItem();
if(selectedMode == SelectionMode.DAY){
if(this.cboDay.getDate() != null){
Calendar toDate = Calendar.getInstance();
toDate.setTime(this.cboDay.getDate());
toDate.add(Calendar.DATE, -this.numberOfPeriods);
SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");
this.lblLowerBoundDate.setText(sdf.format(toDate.getTime()));
}else
this.lblLowerBoundDate.setText("-");
}else if(selectedMode == SelectionMode.WEEK){
Week selectedWeek = (Week)this.cboWeek.getSelectedItem();
if(selectedWeek != null){
Week toWeek = selectedWeek.getLowerBoundWeek();
this.lblLowerBoundDate.setText(toWeek.toString() + " - " + toWeek.year);
}
else{
this.lblLowerBound.setText("");
this.lblLowerBoundDate.setText("");
}
}else if(selectedMode == SelectionMode.MONTH){
Month selectedMonth = (Month)this.cboMonth.getSelectedItem();
if(selectedMonth != null){
Month toMonth = selectedMonth.getLowerBoundMonth();
this.lblLowerBoundDate.setText(toMonth.toString() + " - " + toMonth.year);
}else{
this.lblLowerBound.setText("");
this.lblLowerBoundDate.setText("");
}
}else if(selectedMode == SelectionMode.YEAR){
int selectedYear = (Integer)this.cboYear.getSelectedItem();
if(selectedYear > 0){
this.lblLowerBoundDate.setText(Integer.toString(selectedYear - this.numberOfPeriods));
}else{
this.lblLowerBound.setText("");
this.lblLowerBoundDate.setText("");
}
}
}
}
private void setSelectionDay(){
if(numberOfPeriods == 0)
this.lblUpperBound.setText("V�lg dato:");
else
this.lblUpperBound.setText("Fra:");
this.lblUpperBound.setVisible(true);
this.cboDay.setVisible(true);
this.cboWeek.setVisible(false);
this.cboMonth.setVisible(false);
this.cboYear.setVisible(false);
}
private void setSelectionWeek(){
if(numberOfPeriods == 0)
this.lblUpperBound.setText("V�lg uge:");
else
this.lblUpperBound.setText("Fra:");
this.lblUpperBound.setVisible(true);
this.cboDay.setVisible(false);
this.cboWeek.setVisible(true);
this.cboMonth.setVisible(false);
this.cboYear.setVisible(true);
}
private void setSelectionMonth(){
if(numberOfPeriods == 0)
this.lblUpperBound.setText("V�lg m�ned:");
else
this.lblUpperBound.setText("Fra:");
this.lblUpperBound.setVisible(true);
this.cboDay.setVisible(false);
this.cboWeek.setVisible(false);
this.cboMonth.setVisible(true);
this.cboYear.setVisible(true);
}
private void setSelectionYear(){
if(numberOfPeriods == 0)
this.lblUpperBound.setText("V�lg �r:");
else
this.lblUpperBound.setText("Fra:");
this.lblUpperBound.setVisible(true);
this.cboDay.setVisible(false);
this.cboWeek.setVisible(false);
this.cboMonth.setVisible(false);
this.cboYear.setVisible(true);
}
public void addActionListener(ActionListener listener){
this.actionListeners.add(listener);
}
public void removeActionListener(ActionListener listener){
this.actionListeners.remove(listener);
}
protected void dateSelected(){
for(ActionListener a : this.actionListeners)
a.actionPerformed(new ActionEvent(this, 1, "DateSelected"));
}
@Override
public void actionPerformed(ActionEvent e) {
SelectionMode selectedMode = (SelectionMode)this.cboSelectionMode.getSelectedItem();
if(e.getSource() == this.cboYear){
PeriodSelector.this.updateMonths();
PeriodSelector.this.updateWeeks();
if(selectedMode == SelectionMode.YEAR)
this.dateSelected();
}else if(e.getSource() == this.cboMonth && selectedMode == SelectionMode.MONTH){
this.dateSelected();
}else if(e.getSource() == this.cboWeek && selectedMode == SelectionMode.WEEK){
this.dateSelected();
}else if(e.getSource() == this.cboDay && selectedMode == SelectionMode.DAY){
this.dateSelected();
}
this.updateLowerBoundLabels();
}
private class Week implements Comparable<Week>{
private Integer week;
private Integer year;
public Week(int week, int year){
this.week = week;
this.year = year;
}
public DateTime getLowerBound(){
DateTime firstDateOfWeek = new DateTime(year,
1,
1,
0,
0).withWeekOfWeekyear(this.week);
firstDateOfWeek = firstDateOfWeek.minusWeeks(PeriodSelector.this.numberOfPeriods);
return firstDateOfWeek;
}
public DateTime getUpperBound(){
DateTime lastDateOfWeek = new DateTime(year,
1,
1,
23,
59,
59).withWeekOfWeekyear(this.week);
return lastDateOfWeek;
}
public Week getLowerBoundWeek(){
DateTime lowerBound = this.getLowerBound();
return new Week(lowerBound.getWeekOfWeekyear(), lowerBound.getYear());
}
@Override
public String toString() {
return "Uge " + this.week;
}
@Override
public boolean equals(Object obj) {
if(obj == null) return false;
if(obj instanceof Week){
Week compYear = (Week)obj;
return (compYear.year == this.year && compYear.week == this.week);
}else
return false;
}
@Override
public int compareTo(Week o) {
if(o == null) return -1;
int yearComparison = this.year.compareTo(o.year);
if(yearComparison != 0)
return yearComparison;
else
return this.week.compareTo(o.week);
}
}
private class Month implements Comparable<Month>{
private Integer month;
private Integer year;
public Month(int month, int year){
this.month = month;
this.year = year;
}
public DateTime getLowerBound(){
DateTime firstDateOfMonth = new DateTime(this.year,
this.month,
1,
0,
0,
0);
firstDateOfMonth = firstDateOfMonth.minusMonths(PeriodSelector.this.numberOfPeriods);
return firstDateOfMonth;
}
public DateTime getUpperBound(){
DateTime lastDateOfMonth = new DateTime(this.year,
this.month,
1,
23,
59,
59).dayOfMonth().withMaximumValue();
return lastDateOfMonth;
}
public Month getLowerBoundMonth(){
DateTime lowerBound = this.getLowerBound();
return new Month(lowerBound.getMonthOfYear(), lowerBound.getYear());
}
@Override
public String toString() {
DateTime date = this.getLowerBound();
String monthName = DateTimeFormat.forPattern("MMMM").print(date);
return Character.toUpperCase(monthName.charAt(0)) + monthName.substring(1);
}
@Override
public boolean equals(Object obj) {
if(obj == null) return false;
if(obj instanceof Month){
Month compMonth = (Month)obj;
return (compMonth.year == this.year && compMonth.month == this.month);
}else
return false;
}
@Override
public int compareTo(Month o) {
if(o == null) return -1;
int yearComparison = this.year.compareTo(o.year);
if(yearComparison != 0)
return yearComparison;
else
return this.month.compareTo(o.month);
}
}
private class Year implements Comparable<Year>{
private Integer year;
public Year(int year){
this.year = year;
}
public DateTime getLowerBound(){
DateTime firstDateOfYear = new DateTime(this.year - PeriodSelector.this.numberOfPeriods,
1,
1,
0,
0,
0);
return firstDateOfYear;
}
public DateTime getUpperBound(){
DateTime lastDateOfYear = new DateTime(this.year,
12,
31,
23,
59,
59);
return lastDateOfYear;
}
@Override
public String toString() {
return Integer.toString(this.year);
}
@Override
public boolean equals(Object obj) {
if(obj == null) return false;
if(obj instanceof Year){
Year compYear = (Year)obj;
return (compYear.year == this.year);
}else
return false;
}
@Override
public int compareTo(Year o) {
if(o == null) return -1;
return this.year.compareTo(o.year);
}
}
}